package com.jwsoft.manager.core.integration.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.bifang.engine.assistant.core.annotation.ApiService;
import com.bifang.engine.assistant.core.annotation.OpApi;
import com.bifang.engine.assistant.core.annotation.SaveOplog;
import com.bifang.engine.assistant.core.enums.AuTypeEnum;
import com.bifang.engine.assistant.core.enums.FuncTypeEnum;
import com.bifang.engine.data.core.util.PagerUtil;
import com.bifang.module.base.core.helper.DictHelper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jwsoft.manager.common.constant.EduCache;
import com.jwsoft.manager.common.enums.EduAreaCodeEnum;
import com.jwsoft.manager.common.enums.EnrollStatusFormalEnum;
import com.jwsoft.manager.common.enums.SchoolCategoryEnum;
import com.jwsoft.manager.common.enums.SourceTypeEnum;
import com.jwsoft.manager.common.vo.eduSchool.EduSchoolVO;
import com.jwsoft.manager.core.dao.model.EduSchoolConfig;
import com.jwsoft.manager.core.dao.model.EduStudentEnroll;
import com.jwsoft.manager.core.dao.service.EduSchoolConfigService;
import com.jwsoft.manager.core.dao.service.EduSchoolService;
import com.jwsoft.manager.core.dao.service.EduStudentEnrollService;
import com.jwsoft.manager.core.util.EduHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import cn.hutool.core.convert.Convert;

import java.util.*;
import java.util.stream.Collectors;

import com.bifang.engine.assistant.core.exception.AppException;
import org.springframework.util.ObjectUtils;
import org.springframework.transaction.annotation.Transactional;
import com.bifang.engine.assistant.core.enums.BoolEnum;
import com.jwsoft.manager.common.vo.eduSchoolLr.EduSchoolLrVO;
import com.jwsoft.manager.common.vo.eduSchoolLr.EduSchoolLrKeyVO;
import com.jwsoft.manager.common.vo.eduSchoolLr.EduSchoolLrQueryVO;
import com.jwsoft.manager.core.integration.EduSchoolLrIntegration;
import com.jwsoft.manager.core.dao.service.EduSchoolLrService;
import com.jwsoft.manager.core.dao.model.EduSchoolLr;

/**
 * 学校可线下录入人数指标表管理业务实现类
 *
 * @author zhiyuan
 * @since 2023-08-04
 */
@ApiService(funcCode = "eduSchoolLr", title = "学校可线下录入人数指标表管理")
@Slf4j
public class EduSchoolLrIntegrationImpl implements EduSchoolLrIntegration {

    @Autowired
    public EduSchoolLrService eduSchoolLrService;

    @Autowired
    private EduHelper eduHelper;

    @Autowired
    private EduSchoolService eduSchoolService;

    @Autowired
    private EduStudentEnrollService eduStudentEnrollService;

    @Autowired
    private DictHelper dictHelper;

    @Autowired
    private EduSchoolConfigService eduSchoolConfigService;

    @Autowired
    private RedissonClient redissonClient;
    @Override
    @OpApi(funcCode = "eduSchoolLr0001", title = "学校可线下录入人数指标表管理分页查询", funcType = FuncTypeEnum.query)
    public PageInfo<EduSchoolLrVO> getList(EduSchoolLrQueryVO vo) {
        // 开启分页
        if (vo.getPageNum() == null || vo.getPageSize() == null) {
            //如果不传入分页参数，默认最大取1000条
            vo.setPageNum(1);
            vo.setPageSize(1000);
        }
        PageHelper.startPage(vo.getPageNum(),vo.getPageSize());
        if (ObjectUtils.isEmpty(vo.getYear())){
            vo.setYear(eduHelper.thisYear());
        }
        QueryWrapper<EduSchoolLr> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(EduSchoolLr::getYear,vo.getYear())
                .eq(!ObjectUtils.isEmpty(vo.getSchoolNature()),EduSchoolLr::getSchoolNature,vo.getSchoolNature())
                .eq(!ObjectUtils.isEmpty(vo.getSchoolId()),EduSchoolLr::getSchoolId,vo.getSchoolId())
                .eq(!ObjectUtils.isEmpty(vo.getSchoolCategory()),EduSchoolLr::getSchoolCategory,vo.getSchoolCategory())
                .eq(!ObjectUtils.isEmpty(vo.getAreaCode()),EduSchoolLr::getAreaCode,vo.getAreaCode())
                .orderByDesc(EduSchoolLr::getUpdateTime,EduSchoolLr::getLrCount)
                ;
        List<EduSchoolLr> list = eduSchoolLrService.list(queryWrapper);
        if (CollectionUtils.isEmpty(list)) {
            // 判断是否为空，为空则返回空参数
            return PagerUtil.createEmptyPagerInfo(vo.getPageNum(), vo.getPageSize());
        }
        // 不为空则获取分页结果
        PageInfo<EduSchoolLr> pageInfo = new PageInfo<>(list);
        // 返回参数需要通过common层的vo实体类，用该方法可以批量转换
        List<EduSchoolLrVO> resultList = Convert.toList(EduSchoolLrVO.class, pageInfo.getList());
        // 转义数据字典值
         dictHelper.valueToName(resultList, Arrays.asList(EduAreaCodeEnum.values()));
        return PagerUtil.parsePagerVo(resultList, pageInfo);
    }

    @Override
    @OpApi(funcCode = "eduSchoolLr0002", title = "学校可线下录入人数指标表管理根据主键查询详情", funcType = FuncTypeEnum.query)
    public EduSchoolLrVO getById(EduSchoolLrKeyVO vo) {
        EduSchoolLr entity = eduSchoolLrService.getById(vo.getSchoolLrId());
        if (ObjectUtils.isEmpty(entity)) {
            throw new AppException("查询不到详细信息!");
        }
        EduSchoolLrVO result = Convert.convert(EduSchoolLrVO.class, entity);
        return result;
    }
    /** 保存前统一校验*/
    @Override
    @OpApi(funcCode = "eduSchoolLr0003", title = "学校可线下录入人数指标表管理保存前校验", funcType = FuncTypeEnum.other ,checkPrivilege = BoolEnum.FALSE)
    public void checkSave(EduSchoolLrVO vo) {
        //主键为空为新增校验

        //主键不为空为修改校验
    }

    @Override
    @OpApi(funcCode = "eduSchoolLr0004", title = "学校可线下录入人数指标表管理新增", funcType = FuncTypeEnum.insert)
    @SaveOplog(
            operationType = "eduSchoolLr0004",
            operationName = "学校可线下录入人数指标表管理新增",
            dataType = "schoolLrId",
            auType = AuTypeEnum.OTHER)
    @Transactional
    public EduSchoolLrVO add(EduSchoolLrVO vo) {
        //保存前校验
        if (StringUtils.isBlank(vo.getSchoolId())) {
            throw new AppException("学校id不能为空");
        }
        Integer year = eduHelper.thisYear();
        EduSchoolVO schoolVO = eduSchoolService.getDetail(vo.getSchoolId());
        QueryWrapper<EduSchoolLr> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(EduSchoolLr::getSchoolId,vo.getSchoolId())
                .eq(EduSchoolLr::getYear,year);
        if (eduSchoolLrService.count(queryWrapper) >0){
            throw new AppException("当年度线下录入人数指标已存在，请修改");
        }
        if (vo.getLrCount() == null){
            vo.setLrCount(0);
        }
        vo.setAreaCode(schoolVO.getAreaCode());
        vo.setYear(year);
        vo.setSchoolName(schoolVO.getSchoolName());
        vo.setSchoolNature(schoolVO.getSchoolNature());
        vo.setSchoolCategory(schoolVO.getSchoolCategory());
        //保存数据
        EduSchoolLr entity = Convert.convert(EduSchoolLr.class, vo);
        eduSchoolLrService.save(entity);
        //将主键设置回vo使操作日志可以取到
        vo.setSchoolLrId(entity.getSchoolLrId());
        return vo;
    }

    @Override
    @OpApi(funcCode = "eduSchoolLr0005", title = "学校可线下录入人数指标表管理修改", funcType = FuncTypeEnum.update)
    @SaveOplog(
            operationType = "eduSchoolLr0005",
            operationName = "学校可线下录入人数指标表管理修改",
            dataType = "schoolLrId",
            auType = AuTypeEnum.OTHER)
    @Transactional
    public EduSchoolLrVO edit(EduSchoolLrVO vo) {
        if (ObjectUtils.isEmpty(vo.getSchoolLrId())) {
            throw new AppException("传入需要修改的主键不能为空!");
        }
        EduSchoolLr oldEntity = eduSchoolLrService.getById(vo.getSchoolLrId());
        if (ObjectUtils.isEmpty(oldEntity)) {
            throw new AppException("查询不到需要修改的信息!");
        }
        Integer year = eduHelper.thisYear();
        //保存前校验
        checkSave(vo);
        QueryWrapper<EduStudentEnroll> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(EduStudentEnroll::getYear,year)
                .eq(EduStudentEnroll::getSource,"6")//学校录入
                .eq(EduStudentEnroll::getEnrollStatus, EnrollStatusFormalEnum.lq.getType())
                .eq(EduStudentEnroll::getSchoolId,oldEntity.getSchoolId());
        long count = eduStudentEnrollService.count(queryWrapper);
        if (count > vo.getLrCount()){
            throw new AppException(oldEntity.getSchoolName() +"线下录入人数为"+count+"人，修改的可录入人数不能小于已录入人数");
        }
        //保存数据
        if (vo.getLrCount() != null){
            //修改可录入人数数量
            oldEntity.setLrCount(vo.getLrCount());
             eduSchoolLrService.updateById(oldEntity);
        }else{
            throw new AppException("可录取人数不为空!");
        }
        return vo;
    }

    @Override
    @OpApi(funcCode = "eduSchoolLr0006", title = "学校可线下录入人数指标表管理根据主键删除", funcType = FuncTypeEnum.delete)
    @SaveOplog(
            operationType = "eduSchoolLr0006",
            operationName = "学校可线下录入人数指标表管理删除",
            dataType = "schoolLrId",
            auType = AuTypeEnum.OTHER)
    @Transactional
    public void del(EduSchoolLrKeyVO vo) {
        if (ObjectUtils.isEmpty(vo.getSchoolLrId())) {
            throw new AppException("传入需要删除的数据主键不能为空!");
        }
        EduSchoolLr entity = eduSchoolLrService.getById(vo.getSchoolLrId());
        if (ObjectUtils.isEmpty(entity)) {
            throw new AppException("未找到需要删除的信息!");
        }
        Integer year = eduHelper.thisYear();
        QueryWrapper<EduStudentEnroll> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(EduStudentEnroll::getYear,year)
                .eq(EduStudentEnroll::getSource,"6")//学校录入
                .eq(EduStudentEnroll::getEnrollStatus, EnrollStatusFormalEnum.lq.getType())
                .eq(EduStudentEnroll::getSchoolId,entity.getSchoolId());
        long count = eduStudentEnrollService.count(queryWrapper);
        if(count >0){
            throw new AppException(entity.getSchoolName()+"通过线下录入了学生，不能删除该学校录入指标");
        }

        eduSchoolLrService.removeById(vo.getSchoolLrId());
    }

    @OpApi(funcCode = "eduSchoolLr0007", title = "初始化学校人数指标信息", funcType = FuncTypeEnum.delete)
    @SaveOplog(
            operationType = "eduSchoolLr0007",
            operationName = "初始化学校人数指标信息",
            dataType = "schoolLrId",
            auType = AuTypeEnum.OTHER)
    @Override
    public void initializeSchoolLr(EduSchoolLrKeyVO vo) {
        RLock lock = redissonClient.getLock(EduCache.EDU_SCHOOL_LR_LOCK);

        try {
            boolean lockAcquired = lock.tryLock();
            if (lockAcquired) {
                // 获取锁成功，执行初始化操作
                //从报名配置表中，获取当年度的 配置信息
                List<String> categoryList = new ArrayList<>();
                categoryList.add(SchoolCategoryEnum.PRIMARY.getType());
                categoryList.add(SchoolCategoryEnum.JUNIOR.getType());
                List<EduSchoolConfig> schoolConfigList = eduSchoolConfigService.list(Wrappers.<EduSchoolConfig>lambdaQuery()
                        .eq(EduSchoolConfig::getYear, eduHelper.thisYear())
                        .in(EduSchoolConfig::getSchoolCategory,categoryList)
                        .select(EduSchoolConfig::getSchoolId));

                Integer year = eduHelper.thisYear();
                Map<String, EduSchoolVO> schoolInfoMap = new HashMap<>();
                schoolConfigList.forEach(item -> {
                    EduSchoolVO schoolInfo = eduSchoolService.getDetail(item.getSchoolId());
                    schoolInfoMap.put(item.getSchoolId(), schoolInfo);
                });
                //处理数据 使用parallelStream并行处理
                List<EduSchoolLr> eduSchoolLrs = schoolConfigList.parallelStream().distinct().map(item -> {
                    EduSchoolLr eduSchoolLr = new EduSchoolLr();
                    EduSchoolVO schoolInfo = schoolInfoMap.get(item.getSchoolId());
                    eduSchoolLr.setSchoolId(schoolInfo.getOrgId());
                    eduSchoolLr.setSchoolName(schoolInfo.getSchoolName());
                    eduSchoolLr.setSchoolCategory(schoolInfo.getSchoolCategory());
                    eduSchoolLr.setSchoolNature(schoolInfo.getSchoolNature());
                    eduSchoolLr.setAreaCode(schoolInfo.getAreaCode());
                    eduSchoolLr.setYear(year);
                    //查询学生报名表
                    long count = eduStudentEnrollService.count(Wrappers.<EduStudentEnroll>lambdaQuery()
                            .eq(EduStudentEnroll::getYear, year)
                            .eq(EduStudentEnroll::getSchoolId, item.getSchoolId())
                            .eq(EduStudentEnroll::getEnrollStatus, EnrollStatusFormalEnum.lq.getType())
                            .eq(EduStudentEnroll::getSource, "6") //学校线下录入
                    );
                    eduSchoolLr.setLrCount((int) count);
                    return eduSchoolLr;
                }).filter(item->{
                    //查询配置表是否有
                    long count = eduSchoolLrService.count(Wrappers.<EduSchoolLr>lambdaQuery().eq(EduSchoolLr::getSchoolId, item.getSchoolId()));
                    return count >0 ? false :true;
                }).collect(Collectors.toList());

                if(ObjectUtils.isEmpty(eduSchoolLrs)){
                    throw new AppException("当前年度已经初始化过了，无需再次进行初始化");
                }
                //批量插入
                eduSchoolLrService.saveBatch(eduSchoolLrs);
            } else {
                // 未获取到锁，表示已经有其他请求在处理
                lock.forceUnlock(); // 强制释放锁，确保不发生死锁
                throw new AppException("正在进行初始化，请稍后再试");
            }
        } catch (Exception e) {
            log.error("initializeSchoolLr方法"+e.getMessage());
            throw new AppException(e.getMessage());
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }
}
